package com.ly.juc;
import	java.util.Random;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @Classname TestReentrantLock
 * @Description TODO
 * @Date 2020/10/3 17:44
 * @Author 冷心影翼
 */
public class TestReentrantLock {

	public static void main(String[] args) throws InterruptedException {
		testConditionAccurateNotify();

	}

	//Sync传统方法
	public static void testSync() throws InterruptedException {
		Ticket ticket = new Ticket();
		for(int i=0;i<5;i++) {
			new Thread(()->{
				ticket.saleByReetrantLock();
			}).start();
		}

	}

	//测试锁
	public static void testLock() {
		Ticket ticket = new Ticket();
		for(int i=0;i<5;i++) {
			new Thread(() -> {
				ticket.saleBySynchronized();
			}).start();
		}
	}

	//Object的wait和notify
	public static void testWaitNotify() throws InterruptedException {
		Factory factory = new Factory();
		for(int i=0;i<10;i++) {
			new Thread(()->{
				for(int j=0;j<10;j++)
					factory.productBySync();
			}).start();
			new Thread(()->{
				for(int j=0;j<10;j++)
					factory.consumeBySync();
			}).start();
		}


	}

	//condition的wait和notify
	public static void testCondition() {
		Factory factory = new Factory();
		for(int i=0;i<10;i++) {
			new Thread(()->{
				for(int j=0;j<10;j++)
					factory.productByLock();
			}).start();
			new Thread(()->{
				for(int j=0;j<10;j++)
					factory.consumeByLock();
			}).start();
		}
	}

	//精准唤醒
	public static void testConditionAccurateNotify() {
		FoodFactory foodFactory = new FoodFactory();
		for(int i=0;i<3;i++) {
			new Thread(()->{
				for(int j=0;j<10;j++) {
					foodFactory.buyMaterial();
				}
			}).start();
		}
		for(int i=0;i<3;i++) {
			new Thread(()->{
				for(int j=0;j<10;j++) {
					foodFactory.cook();
				}
			}).start();
		}
		for(int i=0;i<3;i++) {
			new Thread(()->{
				for(int j=0;j<10;j++) {
					foodFactory.sale();
				}
			}).start();
		}

	}
}

class Ticket {
	private int number = 100;

	private Lock lock = new ReentrantLock();

	public synchronized void saleBySynchronized() {
		if(number>0) {
			number--;
			System.out.println(Thread.currentThread().getName()+" "+(100-number));
		}else {
			System.out.println("售罄");
		}
	}
	public void saleByReetrantLock() {
		lock.lock();
		try{
//			boolean b = lock.tryLock();
//			System.out.println(b);
			if(number>0) {
				number--;
				System.out.println(Thread.currentThread().getName()+" "+(100-number));
			}else {
				System.out.println("售罄");
			}
		}catch(Exception e){

		}finally {
			lock.unlock();
		}

	}
}

class Factory{
	private int number = 0;

	private int capacity = 10;

	private Lock lock = new ReentrantLock();

	private Condition condition = lock.newCondition();

	public synchronized void productBySync()  {
		while (number>capacity) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		number++;
		System.out.println(number);
		notifyAll();
	}

	public synchronized void consumeBySync()  {
		/* 虚假唤醒问题
		 * 不能用if，因为多个消费者线程notifyAll唤醒的不只是生产者，其他消费者也会唤醒
		 * 同时进入了number，然后相减，产生负数*/
		while (number<=0) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		number--;
		System.out.println(number);
		notifyAll();
	}

	public  void productByLock() {
		lock.lock();
		try{
			while (number > capacity) {
				condition.await();
			}
			number++;
			System.out.println(number);
			condition.signalAll();
		}catch(Exception e){
			System.out.println(e);
		}finally {
			lock.unlock();
		}

	}

	public  void  consumeByLock() {
		lock.lock();
		try{
			while (number == 0) {
				condition.await();
			}
			number--;
			System.out.println(number);
			condition.signalAll();
		}catch(Exception e){
			System.out.println(e);
		}finally {
			lock.unlock();
		}

	}

}

class FoodFactory{
	private int number = 0;


	private int flag = 0;


	private Lock lock = new ReentrantLock();

	//购买食材
	private Condition buyMaterialCondition = lock.newCondition();

	//做菜
	private Condition cookCondition = lock.newCondition();

	//买
	private Condition saleCondition = lock.newCondition();

	public void buyMaterial() {
		lock.lock();
		try{
			while (flag != 0) {
				buyMaterialCondition.await();
			}
			number++;
			System.out.println("购买了食材,库存为"+number);
			flag = 1;
			cookCondition.signalAll();

		}catch(Exception e){
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}

	public void cook() {
		lock.lock();
		try{
			while (flag != 1 ) {
				cookCondition.await();
			}
			System.out.println("做菜");
			flag = 2;
			saleCondition.signalAll();
		}catch(Exception e){
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}

	public void sale() {
		lock.lock();
		try{
			while (flag != 2 ) {
				saleCondition.await();
			}
			number--;
			System.out.println("卖出了食材:"+number);
			flag = 0;
			buyMaterialCondition.signalAll();
		}catch(Exception e){
			e.printStackTrace();
		}finally {
			lock.unlock();
		}
	}
}